package devcontainer

import (
	"context"
	"encoding/json"
	"io"
	"net/http"

	"code.gitea.io/gitea/models/db"
	"code.gitea.io/gitea/modules/log"
)

type Devcontainer struct {
	Id                   int64  `xorm:"BIGINT pk NOT NULL autoincr                                      'id'                     comment('主键，devContainerId')"`
	Name                 string `xorm:"VARCHAR(64) charset=utf8mb4 collate=utf8mb4_bin UNIQUE NOT NULL  'name'                   comment('devContainer名称，自动生成')"`
	DevcontainerHost     string `xorm:"VARCHAR(256) charset=utf8mb4 collate=utf8mb4_bin NOT NULL        'devcontainer_host'      comment('SSH Host')"`
	DevcontainerPort     uint16 `xorm:"SMALLINT UNSIGNED NOT NULL                                       'devcontainer_port'      comment('SSH Port')"`
	DevcontainerStatus   uint16 `xorm:"SMALLINT UNSIGNED NOT NULL                                       'devcontainer_status'      comment('SSH Status')"`
	DevcontainerUsername string `xorm:"VARCHAR(32) charset=utf8mb4 collate=utf8mb4_bin NOT NULL         'devcontainer_username'  comment('SSH Username')"`
	DevcontainerWorkDir  string `xorm:"VARCHAR(256) charset=utf8mb4 collate=utf8mb4_bin NOT NULL        'devcontainer_work_dir'  comment('SSH 工作路径，典型值 ~/${project_name}，256字节以内')"`
	RepoId               int64  `xorm:"BIGINT NOT NULL  FK('repo_id') REFERENCES repository(id) ON DELETE CASCADE 'repo_id'      comment('repository表主键')"`
	UserId               int64  `xorm:"BIGINT NOT NULL  FK('user_id') REFERENCES user(id) ON DELETE CASCADE 'user_id'            comment('user表主键')"`
	CreatedUnix          int64  `xorm:"BIGINT                                                           'created_unix'           comment('创建时间戳')"`
	UpdatedUnix          int64  `xorm:"BIGINT                                                           'updated_unix'           comment('更新时间戳')"`
}

type DevcontainerOutput struct {
	Id             int64  `xorm:"BIGINT pk NOT NULL autoincr                                      'id'                     comment('主键，devContainerId')"`
	RepoId         int64  `xorm:"BIGINT NOT NULL     unique(uniquename)                                             'repo_id'                comment('repository表主键')"`
	UserId         int64  `xorm:"BIGINT NOT NULL     unique(uniquename)                                             'user_id'                comment('user表主键')"`
	Status         string `xorm:"VARCHAR(255) charset=utf8mb4 collate=utf8mb4_bin NOT NULL  'status'                   comment('status')"`
	Output         string `xorm:"TEXT                                       'output'      comment('output')"`
	Command        string `xorm:"TEXT                                       'command'      comment('command')"`
	ListId         int64  `xorm:"BIGINT NOT NULL        unique(uniquename)                                'list_id'      comment('list_id')"`
	DevcontainerId int64  `xorm:"BIGINT NOT NULL FK('devcontainer_id') REFERENCES devcontainer(id) ON DELETE CASCADE 'devcontainer_id' comment('devcontainer表主键')"`
}

type DevcontainerScript struct {
	Id           int64  `xorm:"BIGINT pk NOT NULL autoincr                        'id'                     comment('主键，devContainerId')"`
	RepoId       int64  `xorm:"BIGINT NOT NULL                                    'repo_id'                comment('repository表主键')"`
	UserId       int64  `xorm:"BIGINT NOT NULL                                    'user_id'                comment('user表主键')"`
	VariableName string `xorm:"NOT NULL                                    'variable_name'            comment('user表主键')"`
}

func init() {

	db.RegisterModel(new(Devcontainer))
	db.RegisterModel(new(DevcontainerScript))
	db.RegisterModel(new(DevcontainerOutput))
}
func GetScript(ctx context.Context, userId, repoID int64) (map[string]string, error) {
	variables := make(map[string]string)
	var devstarVariables []*DevcontainerVariable
	var name []string
	// Devstar level
	// 从远程获取Devstar变量
	client := &http.Client{}
	req, err := http.NewRequest("GET", "http://devstar.cn/variables/export", nil)
	if err != nil {
		log.Error("Failed to create request for devstar variables: %v", err)
	} else {
		resp, err := client.Do(req)
		if err != nil {
			log.Error("Failed to fetch devstar variables: %v", err)
		} else {
			defer resp.Body.Close()
			body, err := io.ReadAll(resp.Body)
			if err != nil {
				log.Error("Failed to read devstar variables response: %v", err)
			} else {

				err = json.Unmarshal(body, &devstarVariables)
				if err != nil {
					log.Error("Failed to unmarshal devstar variables: %v", err)

				}
			}
		}
	}

	// Global
	err = db.GetEngine(ctx).
		Select("variable_name").
		Table("devcontainer_script").
		Where("user_id = ? AND repo_id = ?", 0, 0).
		Find(&name)

	globalVariables, err := db.Find[DevcontainerVariable](ctx, FindVariablesOpts{})
	if err != nil {
		log.Error("find global variables: %v", err)
		return nil, err
	}
	// 过滤出name在variableNames中的变量
	globalVariables = append(devstarVariables, globalVariables...)
	var filteredGlobalVars []*DevcontainerVariable
	for _, v := range globalVariables {
		if contains(name, v.Name) {
			filteredGlobalVars = append(filteredGlobalVars, v)
		}
	}

	// Org / User level
	err = db.GetEngine(ctx).
		Select("variable_name").
		Table("devcontainer_script").
		Where("user_id = ? AND repo_id = ?", userId, 0).
		Find(&name)
	ownerVariables, err := db.Find[DevcontainerVariable](ctx, FindVariablesOpts{OwnerID: userId})
	if err != nil {
		log.Error("find variables of org: %d, error: %v", userId, err)
		return nil, err
	}
	// 过滤出name在variableNames中的变量
	ownerVariables = append(devstarVariables, ownerVariables...)
	var filteredOwnerVars []*DevcontainerVariable
	for _, v := range ownerVariables {
		if contains(name, v.Name) {
			filteredOwnerVars = append(filteredOwnerVars, v)
		}
	}
	// Repo level
	err = db.GetEngine(ctx).
		Select("variable_name").
		Table("devcontainer_script").
		Where("repo_id = ?", repoID).
		Find(&name)
	repoVariables, err := db.Find[DevcontainerVariable](ctx, FindVariablesOpts{RepoID: repoID})
	if err != nil {
		log.Error("find variables of repo: %d, error: %v", repoID, err)
		return nil, err
	}
	// 过滤出name在variableNames中的变量
	repoVariables = append(devstarVariables, repoVariables...)
	var filteredRepoVars []*DevcontainerVariable
	for _, v := range repoVariables {
		if contains(name, v.Name) {
			filteredRepoVars = append(filteredRepoVars, v)
		}
	}
	// Level precedence: Org / User > Repo > Global
	for _, v := range append(filteredGlobalVars, append(filteredRepoVars, filteredOwnerVars...)...) {
		variables[v.Name] = v.Data
	}

	return variables, nil
}

// contains 检查字符串切片中是否包含指定的字符串
func contains(slice []string, item string) bool {
	for _, s := range slice {
		if s == item {
			return true
		}
	}
	return false
}
